﻿using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public abstract class StoryAction : IReusableClassWithFree
    {
        protected UIStory ui;
        public GameObject root { get; private set; }
        protected StoryActionData data;
        private CancellationTokenSource _cancel;
        private readonly Dictionary<EStoryActionDynamicKey, object> _dynamicParam = new();

        public bool Initialize(UIStory ui, GameObject root, StoryActionData data)
        {
            this.ui = ui;
            this.root = root;
            this.data = data;
            return this.OnInitialize(root, data);
        }

        public void BindDynamic(EStoryActionDynamicKey key, object value)
        {
            this._dynamicParam[key] = value;
            this.OnBindDynamic(key, value);
        }

        protected virtual void OnBindDynamic(EStoryActionDynamicKey key, object value)
        {
        }

        protected T GetDynamic<T>(EStoryActionDynamicKey key)
        {
            if (this._dynamicParam.TryGetValue(key, out var rDynamicValue) && rDynamicValue is T t)
            {
                return t;
            }
            return default;
        }

        public void BeforeStart()
        {
            this.OnBeforeStart();
        }
        
        public async UniTask Start()
        {
            this._cancel = new CancellationTokenSource();
            await this.OnStart(this._cancel.Token);
            // this._cancel?.Dispose();
            this._cancel = null;
        }

        public void Update(float dt)
        {
            this.OnUpdate(dt);
        }
        
        public void BeforeEnd()
        {
            this.OnBeforeEnd();
        }

        public async UniTask End()
        {
            if (this._cancel != null)
            {
                this._cancel.Cancel();
                // this._cancel.Dispose();
            }
            this._cancel = new CancellationTokenSource();
            await this.OnEnd(this._cancel.Token);
            // this._cancel?.Dispose();
            this._cancel = null;
        }

        // 注意，dispose可能是因为操控节点重复导致前一节点被覆盖的调用，在end之前
        public void Dispose()
        {
            if (this._cancel != null)
            {
                this._cancel.Cancel();
                // this._cancel.Dispose();
                this._cancel = null;
            }
            this._dynamicParam.Clear();
            this.OnDispose();
            this.Free();
        }

        protected virtual bool OnInitialize(GameObject root, StoryActionData data)
        {
            return false;
        }
        
        protected virtual void OnBeforeStart()
        {
        }

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        protected virtual async UniTask OnStart(CancellationToken cancel)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
        }

        protected virtual void OnUpdate(float dt)
        {
        }

        protected virtual void OnBeforeEnd()
        {
        }

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        protected virtual async UniTask OnEnd(CancellationToken cancel)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
        }

        protected virtual void OnDispose()
        {
        }

        public uint MaxStore => 5;

        public virtual void OnReset()
        {
            this.root = null;
            this.data = null;
            this._cancel = null;
            this.ui = null;
        }

        public abstract void Free();
    }
}